using System.Collections.Generic;
using System.Xml;
using CosyTrade.Core;

namespace CosyTrade.UI
{
    [Addin("PluginManager")]
    public class PluginManager : AddinBase, IPluginManager
    {
        private readonly Dictionary<string, PluginInformaction> pluginInfoCache = new Dictionary<string, PluginInformaction>();
        private readonly List<IPlugin> livePlugins = new List<IPlugin>();
        private readonly List<IMenuItem> menuItems = new List<IMenuItem>();

        protected override void OnInitialize()
        {
            base.OnInitialize();

            XmlNode menus = ConfigNode.SelectSingleNode("Menus");
            int orderIndex = 0;
            foreach (XmlNode node in menus.ChildNodes)
            {
                if (node.Name == "Menu")
                {
                    SubMenuItem subMenu = BuildSubMenuItem(node, orderIndex++);
                    LoadingMenu(node, subMenu);
                    menuItems.Add(subMenu);
                }
                else if (node.Name == "Command")
                {
                    CommandMenuItem cmdMenu = BuildCommandMenuItem(node, orderIndex++);
                    menuItems.Add(cmdMenu);
                }
            }
        }

        private void LoadingMenu(XmlNode parentNode, SubMenuItem parentItem)
        {
            int orderIndex = 0;
            foreach (XmlNode node in parentNode.ChildNodes)
            {
                if (node.Name == "Menu")
                {
                    SubMenuItem subMenu = BuildSubMenuItem(node, orderIndex++);
                    LoadingMenu(node, subMenu);
                }
                else if (node.Name == "Command")
                {
                    CommandMenuItem cmdMenu = BuildCommandMenuItem(node, orderIndex++);
                    parentItem.Items.Add(cmdMenu);
                }
            }
        }

        private static SubMenuItem BuildSubMenuItem(XmlNode node, int orderIndex)
        {
            SubMenuItem subMenu = new SubMenuItem();
            subMenu.MenuId = node.Attributes["MenuID"].InnerText;
            subMenu.Caption = node.Attributes["MenuCaption"].InnerText;
            subMenu.Enable = true;
            subMenu.OrderIndex = orderIndex;
            subMenu.Visible = true;
            return subMenu;
        }

        private CommandMenuItem BuildCommandMenuItem(XmlNode node, int orderIndex)
        {
            CommandMenuItem cmdMenu = new CommandMenuItem();
            cmdMenu.MenuId = node.Attributes["MenuID"].InnerText;
            cmdMenu.Caption = node.Attributes["MenuCaption"].InnerText;
            cmdMenu.PluginKey = node.Attributes["PluginKey"].InnerText;
            cmdMenu.Enable = true;
            cmdMenu.OrderIndex = orderIndex;
            cmdMenu.Visible = true;
            PluginInformaction pluginInfo = new PluginInformaction();
            pluginInfo.PluginKey = cmdMenu.PluginKey;
            pluginInfo.PluginStat = PluginStat.Standby;
            pluginInfoCache[pluginInfo.PluginKey] = pluginInfo;
            return cmdMenu;
        }
        
        public IList<IMenuItem> RootMenus
        {
            get { return menuItems; }
        }

        public IPlugin LoadPlugin(string pluginKey)
        {
            if (!pluginInfoCache.ContainsKey(pluginKey)) throw new System.ArgumentException();

            foreach (IPlugin plugin in livePlugins)
                if (plugin.PluginKey == pluginKey) return plugin;

            IPlugin pluginForAddin = (IPlugin) CurrentAddinManager.GetAddin(pluginKey);
            if (pluginForAddin == null) throw new System.NotSupportedException();
            pluginInfoCache[pluginKey].Plugin = pluginForAddin;
            pluginInfoCache[pluginKey].PluginStat = PluginStat.Running;
            LivePlugins.Add(pluginInfoCache[pluginKey].Plugin);
            return pluginInfoCache[pluginKey].Plugin;
        }

        public void FreePlugin(IPlugin plugin)
        {
            if (LivePlugins.Contains(plugin))
                LivePlugins.Remove(plugin);
            pluginInfoCache[plugin.PluginKey].Plugin = null;
            pluginInfoCache[plugin.PluginKey].PluginStat = PluginStat.Standby;
        }

        public List<IPlugin> LivePlugins
        {
            get { return livePlugins; }
        }
    }

    class PluginInformaction
    {
        private string pluginKey;
        private IPlugin plugin;
        private PluginStat pluginStat;
        
        public string PluginKey
        {
            get { return pluginKey; }
            set { pluginKey = value; }
        }
        
        public IPlugin Plugin
        {
            get { return plugin; }
            set { plugin = value; }
        }

        public PluginStat PluginStat
        {
            get { return pluginStat; }
            set { pluginStat = value; }
        }
    }

    enum PluginStat
    {
        Standby,
        Running,
    }
}